/**
 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { E } from "std/math";

{%- if item.init_object_complex_constructor is defined %}
{%- for number in item.init_object_param_list.keys() %}
const TEST_DATA_OBJECT_INIT_{{.number|upper}} : {{.item.init_object_data_types[number]}} = {{.item.init_object_param_list[number]}};
{%- endfor %}
{%- else %}
const TEST_DATA_OBJECT_INIT : {{.item.init_object_data_type}} ={{.item.init_object_data}};
{%- endif %}
{%- for number, param in item.param_list.items() %}
const TEST_DATA_{{.number|upper}} : {{.item.param_init_data_types[number]}} = {{.item.param_list[number]}};
{%- endfor %}
const TEST_DATA_EXPECTED : {{.item.expected_data_type}} = {{.item.expected_test_data}};

function main(): int {
  let exp_idx : int = 0
{%- if item.max_attempt is defined %}
  let max_test : int = {{.item.max_attempt}}
{%- else %}
  {% if item.param_list | length > 0 %}
    let max_step : int = TEST_DATA_{{.item.param_list.keys()|first|upper}}.length as int;
  {% else %}
    let max_step : int = TEST_DATA_EXPECTED.length as int;
  {% endif %}
  let max_test : int = TEST_DATA_EXPECTED.length as int;
{%- endif %}
  let passed_counter : int = 0;
  for (let i = 0; i < max_step; i++, exp_idx++) {
      {%- if item.init_object_complex_constructor is defined %}
        {%- for number in item.init_object_param_list.keys() %}
          {%- if item.init_object_param_nature[number] == "object" %}
              let {{.number}} : {{.item.init_object_param_types[number]}} = new {{.item.init_object_param_types[number]}}(TEST_DATA_OBJECT_INIT_{{.number|upper}}[i]);
          {%- else %}
              let {{.number}} : {{.item.init_object_param_types[number]}} = TEST_DATA_OBJECT_INIT_{{.number|upper}}[i];
          {%- endif %}
        {%- endfor %}
        let obj{{.item.object_type}} : {{.item.object_type}} = new {{.item.object_type}}({{.item.init_object_param_list.keys()|join(', ')}});
      {%- else %}
        let obj{{.item.object_type}} : {{.item.object_type}} = new {{.item.object_type}}(TEST_DATA_OBJECT_INIT[i]);
      {%- endif %}
  {%- for number, param in item.param_list.items() %}
    {%- if item.param_nature[number] == "object" %}
      let {{.number}} : {{.item.param_types[number]}} = new {{.item.param_types[number]}}(TEST_DATA_{{.number|upper}}[i]);
    {%- else %}
      {%- if item.param_nature[number] == "regexp" %}
        let {{.number}} : {{.item.param_types[number]}} = new {{.item.param_types[number]}}(TEST_DATA_{{.number|upper}}[i], "g");
      {%- else %}
        let {{.number}} : {{.item.param_types[number]}} = (TEST_DATA_{{.number|upper}}[i]);
      {%- endif %}
    {%- endif %}
  {%- endfor %}

  {%- if item.method_throws == true %}
        let exceptionTypeMatched: boolean = false;
        let actualExceptionMessage: string = "";
  {%- endif %}
  {%- if item.method_return_type == "void" %}
        {%- if item.method_throws == true %} try { {%- endif %}
        obj{{.item.object_type}}.{{.item.method_name}}({{.item.param_list.keys()|list|join(', ')}});
        {%- if item.method_throws == true %} } catch (e) { console.println("Unexpected exception in positive test"); } {%- endif %}
    {% if item.result_storage == "this" %}
        {% set actualType = item.result_type %}
        let actual: {{.actualType}};
        actual = obj{{.item.object_type}}.{{.item.result_retrieve_function}};
    {%- endif %}
  {% else %}
        {% set actualType = item.method_return_type %}
        let actual: {{.actualType}}{% if item.method_throws == true %} | undefined | null{%- endif %}{%- if item.init_object_init_value is defined %} = {{.item.init_object_init_value}}{%- endif %};
      {% if item.method_throws == true %} try { {%- endif %}
        {%- if item.method_name == "codePointAt" %}
      let tmp: Number | undefined = obj{{.item.object_type}}.{{.item.method_name}}({{.item.param_list.keys()|list|join(', ')}});
      if (tmp == undefined) {
        console.print("FAILED");
        console.println();
        continue;
      }
        actual = tmp.toDouble();
        {%- else %}
        actual = obj{{.item.object_type}}.{{.item.method_name}}({{.item.param_list.keys()|list|join(', ')}});
        {%- endif %}
      {% if item.method_throws == true %} }
        {%- if item.expected_exception_type is defined %}
          catch (e: {{.item.expected_exception_type}}) {
            exceptionTypeMatched = true
            actualExceptionMessage = e.message
          }
        {%- endif %}
          catch (e) {
            if (e instanceof Exception) {
              actualExceptionMessage = e.toString()
            }
          }
      {%- endif %}

  {%- endif %}
  {%- for number, param in item.param_list.items() %}
//      console.print("{{.number}} = " + {{.number}} + ";");
  {%- endfor %}
//      console.print("ACTUAL:" + actual + ";");
//      console.print("EXPECTED:" + TEST_DATA_EXPECTED[exp_idx] + ";");
      {% if item.method_throws == true %}
      if (actual instanceof undefined || actual instanceof null) {
        // Exception caught
        {%- if item.expected_exception_type is defined %}
        if (!exceptionTypeMatched) {
          console.print("FAILED: Unexpected exception");
          console.println();
          continue;
        }
          {% if item.expected_exception_message is defined %}
        if (!compareStringTrivial(actualExceptionMessage, "{{.item.expected_exception_message}}")) {
          console.print("FAILED: Unexpected exception message: " + actualExceptionMessage);
          console.println();
          continue;
        }
        console.print("PASSED");
        console.println();
        passed_counter++;
        continue;
          {%- endif %}
        {%- else %}
        console.print("FAILED: Unexpected exception in positive test. Additional info: " + actualExceptionMessage);
        console.println();
        continue;
        {%- endif %}
      } else {
        // No exception occurs. Check test result
        let expected = TEST_DATA_EXPECTED[exp_idx];
        {% raw %}// Workaround possible verifier bug, since we can't simply write: "actual as {{.actualType}}" for primitive types {% endraw %}
        if ({{.item.verify_test_result_function}}(() => { return actual }() as {{.actualType}}, expected)) {
      {%- else %}
        // No exception occurs. Check test result
        let expected = TEST_DATA_EXPECTED[exp_idx];
        if ({{.item.verify_test_result_function}}(actual, expected)) {
      {%- endif %}
          console.print("PASSED");
          passed_counter++;
        } else {
          console.print("FAILED");
        {%- if item.message_on_fail is defined and not item.method_throws %}
          console.print(`: {{.item.message_on_fail}}`);
        {%- endif %}
        }
        console.println();
      {% if item.method_throws == true %}}{%- endif %}
    }
  assertEQ(passed_counter, max_test)
  return 0;
  }
